package com.example.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.entity.dto.Account;
import com.example.entity.vo.request.ConfirmResetVO;
import com.example.entity.vo.request.CreateSubAccountVO;
import com.example.entity.vo.request.EmailRestVO;
import com.example.entity.vo.request.ModifyEmailVO;
import com.example.entity.vo.response.SubAccountVO;
import com.example.mapper.AccountMapper;
import com.example.service.AccountService;
import com.example.utils.Const;
import com.example.utils.FlowUtils;
import com.example.utils.JwtUtils;
import jakarta.annotation.Resource;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    @Resource
    AmqpTemplate amqpTemplate;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Resource
    FlowUtils flowUtils;
    @Resource
    JwtUtils jwtUtils;

    @Resource
    PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = this.findAccountByNameOrEmail(username);
        if (account == null) {
            throw new UsernameNotFoundException("用户名或密码错误");
        }
        return User
                .withUsername(username)
                .password(account.getPassword())
                .roles(account.getRole())
                .build();
    }


    @Override
    public Account findAccountByNameOrEmail(String text) {
        return this.query()
                .eq("username", text)
                .or()
                .eq("email", text)
                .one();
    }

    @Override
    public String registerEmailVerifyCode(String type, String email, String ip) {
        synchronized (ip.intern()) {
            if (!this.verifyLimit(ip)) {
                return "请求过于频繁";
            }
            Random random = new Random();
            int code = random.nextInt(899999) + 100000;
            Map<String, Object> data = Map.of("type", type, "email", email, "code", code);
            amqpTemplate.convertAndSend("mail", data);
            stringRedisTemplate.opsForValue()
                    .set(Const.VERIFY_EMAIL_DATA + email, String.valueOf(code), 3, TimeUnit.MINUTES);
            return null;
        }
    }

//    @Override
//    public String registerEmailAccount(EmailRegisterVO emailRegisterVO) {
//        String email = emailRegisterVO.getEmail();
//        String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA + email);
//        if (code == null || !code.equals(emailRegisterVO.getCode())) {
//            return "验证码错误";
//        }
//        if (this.existsAccountByEmail(email)) {
//            return "邮箱已被注册";
//        }
//        if (this.existsAccountByUsername(emailRegisterVO.getUsername())) {
//            return "用户名已被注册";
//        }
//        Account account = new Account(null, emailRegisterVO.getUsername(), passwordEncoder.encode(emailRegisterVO.getPassword()), email, "user", new Date());
//        if (this.save(account)) {
//            stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA + email);
//            return null;
//        } else {
//            return "内部错误，请稍后再试";
//        }
//    }

    @Override
    public String restConfirm(ConfirmResetVO vo) {
        String email = vo.getEmail();
        String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA + email);
        if (code == null) {
            return "请先获取验证码";
        }
        if (!code.equals(vo.getCode())) {
            return "验证码错误";
        }
        return null;

    }

    @Override
    public String restEmailAccountPassword(EmailRestVO vo) {
        String email = vo.getEmail();
        String verify = this.restConfirm(new ConfirmResetVO(email, vo.getCode()));
        if (verify != null) {
            return verify;
        }
        String password = passwordEncoder.encode(vo.getPassword());
        boolean update = this.update().eq("email", email).set("password", password).update();
        if(update){
            stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA + email);
        }
        return null;
    }

    @Override
    public boolean changePassword(int id, String oldPass, String newPass) {
        Account account = this.getById(id);
        String password = account.getPassword();
        if(!passwordEncoder.matches(oldPass, password))
            return false;
        this.update(Wrappers.<Account>update().eq("id", id)
                .set("password", passwordEncoder.encode(newPass)));
        return true;
    }

    @Override
    public void createSubAccount(CreateSubAccountVO vo) {
        Account account = this.findAccountByNameOrEmail(vo.getEmail());
        if (account != null) {
            throw new IllegalArgumentException("该电子邮件已被注册");
        }
        account = this.findAccountByNameOrEmail(vo.getUsername());
        if (account != null) {
            throw new IllegalArgumentException("该用户名已被注册");
        }
        account = new Account(null, vo.getUsername(), passwordEncoder.encode(vo.getPassword()),
                vo.getEmail(), Const.ROLE_NORMAL, new Date(), JSONArray.copyOf(vo.getClients()).toJSONString());
        this.save(account);

    }

    @Override
    public void deleteSubAccount(int uid) {
        jwtUtils.deleteUser(uid);
        this.removeById(uid);
    }

    @Override
    public List<SubAccountVO> listSubAccount() {
        return this.list(Wrappers.<Account>query().eq("role", Const.ROLE_NORMAL))
                .stream().map(account -> {
                    SubAccountVO vo = new SubAccountVO();
                    vo.setId(account.getId());
                    vo.setUsername(account.getUsername());
                    vo.setEmail(account.getEmail());
                    vo.setClientList(JSONArray.parse(account.getClients()));
                    return vo;
                }).toList();
    }

    @Override
    public String modifyEmail(int id, ModifyEmailVO vo) {
        String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA + vo.getEmail());
        if (code == null) return "请先获取验证码";
        if(!code.equals(vo.getCode())) return "验证码错误，请重新输入";
        stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA +  vo.getEmail());
        Account account = this.findAccountByNameOrEmail(vo.getEmail());
        if(account != null && account.getId() != id) return "该邮箱账号已经被其他账号绑定，无法完成操作";
        this.update()
                .set("email", vo.getEmail())
                .eq("id", id)
                .update();
        return null;
    }
//    private boolean existsAccountByEmail(String email) {
//        return this.baseMapper.exists(Wrappers.<Account>query().eq("email", email));
//    }
//
//    private boolean existsAccountByUsername(String username) {
//        return this.baseMapper.exists(Wrappers.<Account>query().eq("username", username));
//    }

    private boolean verifyLimit(String ip) {
        String key = Const.VERIFY_EMAIL_LIMIT + ip;
        return flowUtils.limitOnceCheck(key,60);
    }
}
